/******************************************************************************
 * FileName:    gwin_protocol_task.c
 * Desc:        协议
 *
 *
 * Author:      Lin
 * Notes:
 *
 ******************************************************************************/

/*-------------------------- Includes ---------------------------------------*/
#include "gwin_protocol_task.h"
#include "gwin_main_task.h"
#include "gwin_security.h"
#include "gwin_spec.h"


/*-------------------------- Macro Definitions ------------------------------*/
#define LOCAL_DEBUG_EN                      ( 0 )
#if LOCAL_DEBUG_EN
#define GWIN_DEBUG(...)                     USER_DEBUG(__VA_ARGS__)
#else
#define GWIN_DEBUG(...)
#endif


#define GWIN_PROTOCOL_TASK_PRIORITY         ( 2 )       // 任务优先级，值越大优先级越高       保证主任务优先级最高！！！保证低优先级任务调用！！！否则 gwin_main_cfg_get 会有问题！！！
#define GWIN_PROTOCOL_TASK_STACK_SIZE       ( 2048 )    // 任务栈
#define GWIN_PROTOCOL_TASK_QUEUE_MAX_NUM    ( 32 )      // 消息队列


#define GWIN_PROT_FIFO_MAX_LEN              ( 1024 )
#define GWIN_PROT_LIST_MAX_LEN              ( 16 )


/*-------------------------- Type Declarations ------------------------------*/
/*----------- MCU串口协议 -----------*/
/**
 * @brief 协议 偏移
 *
 *      串口协议：   包头id（2Byte） + 指令类型（1Byte） + 数据长度（2Byte） + 数据内容（N Byte） + 和校验（1Byte） + 包尾（1Byte）
 *
 */
typedef enum _gwin_protocol_index
{
    GWIN_PROT_INDEX_HEAD_1,
    GWIN_PROT_INDEX_HEAD_2,
    GWIN_PROT_INDEX_CMD,
    GWIN_PROT_INDEX_PAYLOAD_LEN_1,
    GWIN_PROT_INDEX_PAYLOAD_LEN_2,
    GWIN_PROT_INDEX_PAYLOAD_DATA,
    GWIN_PROT_INDEX_MAX,
}gwin_protocol_index_t;
#define GWIN_PROT_HEAD_SEND                 ( 0xAA55 )          // 包头 模组 -> MCU
#define GWIN_PROT_HEAD_RECV                 ( 0x55AA )          // 包头 MCU -> 模组
#define GWIN_PROT_MIN_LEN                   ( GWIN_PROT_INDEX_MAX - 1 )             // 最小总长度

/**
 * @brief 协议回复
 */
typedef enum _gwin_protocol_ack
{
    GWIN_PROT_ACK_FAIL,
    GWIN_PROT_ACK_SUCCESS,
}gwin_protocol_ack_t;


/**
 * @brief model、pid命令数据域位置
 *          纯字符串格式，分隔符是空格，model、pid是必须，后续参数是可选
 *          格式： model pid version miot_security_siid
 *          例：  giot.light.v8ssm 15504 0017 8
 */
typedef enum _gwin_prot_model_pid_index
{
    GWIN_PROT_MODEL_PID_SEC_INDEX_MODEL,
    GWIN_PROT_MODEL_PID_SEC_INDEX_PID,
    GWIN_PROT_MODEL_PID_SEC_INDEX_VERSION,
    GWIN_PROT_MODEL_PID_SEC_INDEX_MIOT_SECURITY_SIID,
    GWIN_PROT_MODEL_PID_SEC_INDEX_MAX,
}gwin_prot_model_pid_index_t;
#define GWIN_PROT_MODEL_PID_SEC_INDEX_MIN               ( GWIN_PROT_MODEL_PID_SEC_INDEX_PID )
#define GWIN_PROT_MODEL_PID_SEP_SYMBOL                  ' '
#define GWIN_PROT_MODEL_PID_DEFAULT_SYMBOL              '/'


/**
 * @brief 配网超时
 */
typedef enum _gwin_prot_network_timeout
{
    GWIN_PROT_NETWORK_TIMEOUT_MINUTE_2,
    GWIN_PROT_NETWORK_TIMEOUT_MINUTE_10,
    GWIN_PROT_NETWORK_TIMEOUT_MINUTE_30,
    GWIN_PROT_NETWORK_TIMEOUT_MINUTE_MAX,
}gwin_prot_network_timeout_t;

/**
 * @brief 协议命令
 */
typedef struct _gwin_protocol_cmd_map
{
    uint8_t cmd;
    void (*func) (uint8_t cmd, uint8_t *data, uint16_t len);
}gwin_protocol_cmd_map_t;


/**
 * @brief 协议缓存
 */
typedef struct
{
    gwin_fifo_t fifo;
    uint8_t buf[GWIN_PROT_FIFO_MAX_LEN];
}gwin_protocol_fifo_t;

/**
 * @brief 协议队列
 */
typedef struct
{
    gwin_fifo_t fifo;
    uint8_t buf[GWIN_PROT_LIST_MAX_LEN];
}gwin_protocol_list_t;


/*-------------------------- Global Variables -------------------------------*/

/*-------------------------- Local Variables --------------------------------*/
static void *gwin_protocol_task_handle; //!< APP Task handle
static void *gwin_protocol_queue_handle = NULL;


static void gwin_protocol_ack(uint8_t cmd, uint8_t result);
static void gwin_protocol_adv_recv(uint8_t way, uint8_t *data, uint16_t len);
static void gwin_protocol_spec_to_cloud(uint8_t cmd, uint8_t *data, uint16_t len);
static void gwin_protocol_spec_to_mcu(uint8_t *data, uint16_t len);
static void gwin_protocol_spec_string_to_cloud(uint8_t cmd, uint8_t *data, uint16_t len);
static void gwin_protocol_spec_string_to_mcu(uint8_t *data, uint16_t len);
static void gwin_protocol_sys_state(uint8_t cmd, uint8_t *data, uint16_t len);
static void gwin_protocol_low_pwr(uint8_t cmd, uint8_t *data, uint16_t len);
static void gwin_protocol_model_pid_set(uint8_t cmd, uint8_t *data, uint16_t len);
static void gwin_protocol_model_pid_get(uint8_t cmd, uint8_t *data, uint16_t len);
static void gwin_protocol_verification_code(uint8_t cmd, uint8_t *data, uint16_t len);
static void gwin_protocol_active_pair(uint8_t cmd, uint8_t *data, uint16_t len);
static void gwin_protocol_network(uint8_t cmd, uint8_t *data, uint16_t len);
static void gwin_protocol_query(uint8_t cmd, uint8_t *data, uint16_t len);
static void gwin_protocol_build_time(uint8_t cmd, uint8_t *data, uint16_t len);
static void gwin_protocol_fw_name_total(uint8_t cmd, uint8_t *data, uint16_t len);
static void gwin_protocol_fw_version(uint8_t cmd, uint8_t *data, uint16_t len);
static void gwin_protocol_utc(uint8_t cmd, uint8_t *data, uint16_t len);
static void gwin_protocol_weather(uint8_t cmd, uint8_t *data, uint16_t len);
static void gwin_protocol_reset_all_force(uint8_t cmd, uint8_t *data, uint16_t len);
static void gwin_protocol_pair_mode(uint8_t cmd, uint8_t *data, uint16_t len);


/**
 * @brief 协议命令
 */
static const gwin_protocol_cmd_map_t gwin_protocol_cmd_map[] =
{
    { GWIN_PROT_CMD_SPEC,                               gwin_protocol_spec_to_cloud,            },
    { GWIN_PROT_CMD_SPEC_STRING,                        gwin_protocol_spec_string_to_cloud,     },

    { GWIN_PROT_CMD_SYS_STATE,                          gwin_protocol_sys_state,                },
    { GWIN_PROT_CMD_LOW_PWR,                            gwin_protocol_low_pwr,                  },

    { GWIN_PROT_CMD_MODEL_PID_SET,                      gwin_protocol_model_pid_set,            },
    { GWIN_PROT_CMD_MODEL_PID_GET,                      gwin_protocol_model_pid_get,            },
    { GWIN_PROT_CMD_VERIFICATION_CODE,                  gwin_protocol_verification_code,        },
    { GWIN_PROT_CMD_ACTIVE_PAIR,                        gwin_protocol_active_pair,              },
    { GWIN_PROT_CMD_NETWORK,                            gwin_protocol_network,                  },

    { GWIN_PROT_CMD_QUERY,                              gwin_protocol_query,                    },

    { GWIN_PROT_CMD_BUILD_TIME,                         gwin_protocol_build_time,               },
    { GWIN_PROT_CMD_FW_NAME_TOTAL,                      gwin_protocol_fw_name_total,            },
    { GWIN_PROT_CMD_FW_VERSION,                         gwin_protocol_fw_version,               },
    { GWIN_PROT_CMD_UTC,                                gwin_protocol_utc,                      },
    { GWIN_PROT_CMD_WEATHER,                            gwin_protocol_weather,                  },

    { GWIN_PROT_CMD_RESET_ALL_FORCE,                    gwin_protocol_reset_all_force,          },
    { GWIN_PROT_CMD_PAIR_MODE,                          gwin_protocol_pair_mode,                },
};
static const uint8_t gwin_protocol_cmd_map_cnt = sizeof(gwin_protocol_cmd_map) / sizeof(gwin_protocol_cmd_map[0]);

#if (GWIN_PROT_RX_IRQ && !GWIN_PROT_RX_IRQ_RTOS_QUEUE)
_os_timer_declaration(uart_rx);
#endif
_os_timer_declaration(uart_tx);

static uint8_t protocol_task_init = 0;
#if GWIN_PROT_RX_IRQ
static gwin_protocol_fifo_t protocol_fifo_rx_mcu = { 0x00 };
static gwin_protocol_list_t protocol_list_rx_mcu = { 0x00 };
#endif
static gwin_protocol_fifo_t protocol_fifo_tx_mcu = { 0x00 };
static gwin_protocol_list_t protocol_list_tx_mcu = { 0x00 };


/*-------------------------- Functions Declarations -------------------------*/
static void gwin_protocol_task(void *arg);
#if GWIN_PROT_RX_IRQ
static void gwin_protocol_uart_rx_callback(void *arg);
#endif
static void gwin_protocol_uart_tx_callback(void *arg);

static void gwin_protocol_task_timer_msg_handle(gwin_protocol_task_msg_t *msg);
static void gwin_protocol_task_recv_msg_handle(gwin_protocol_task_msg_t *msg);
static void gwin_protocol_task_send_msg_handle(gwin_protocol_task_msg_t *msg);

static void gwin_protocol_send_to_mcu(uint8_t *data, uint16_t len);
static int8_t gwin_protocol_recv_from_mcu(uint8_t *data, uint16_t len);
static uint16_t gwin_protocol_pack_to_mcu(uint8_t *data, uint8_t cmd, uint16_t payload_len);
static void gwin_protocol_parse_from_mcu(uint8_t *data, uint16_t len);
static void gwin_protocol_parse_from_ble(uint8_t way, uint8_t *data, uint16_t len);


/*-------------------------- Functions Definitions --------------------------*/
/*----------- 协议解析 -----------*/
/**
 * @brief 回复，成功/失败
 */
static void gwin_protocol_ack(uint8_t cmd, uint8_t result)
{
    uint8_t buf[GWIN_UART_MAX_LEN] = { 0x00 };
    uint8_t *payload_data = &buf[GWIN_PROT_INDEX_PAYLOAD_DATA];
    uint16_t payload_len = 0;
    uint16_t total_len = 0;

    payload_data[payload_len] = result;
    payload_len += 1;

    total_len = gwin_protocol_pack_to_mcu(buf, cmd, payload_len);
    gwin_protocol_send_to_mcu(buf, total_len);
}


/**
 * @brief 发送某个命令
 */
void gwin_protocol_send_cmd_to_mcu(uint32_t _cmd)
{
    uint8_t buf[GWIN_UART_MAX_LEN] = { 0x00 };
    uint8_t *payload_data = &buf[GWIN_PROT_INDEX_PAYLOAD_DATA];
    uint16_t payload_len = 0;
    uint16_t total_len = 0;
    uint8_t find = 0;

    uint8_t cmd = _cmd;
    switch (cmd)
    {
        case GWIN_PROT_CMD_SYS_STATE:
            {
                find = 1;
                uint8_t param = ((_cmd >> 8) & 0xFF);
                payload_data[payload_len] = (param != 0 ? param : gwin_get_system_state());
                payload_len += 1;
            }
            break;

        case GWIN_PROT_CMD_MODEL_PID_RSQ:
            {
                find = 1;
                payload_data[payload_len] = 0;
                payload_len += 1;
            }
            break;

        case GWIN_PROT_CMD_MODEL_PID_GET:
            {
                find = 1;

                uint8_t str[48] = { 0x00 };
                uint8_t len = 0;

                system_param_product_t product = { 0x00 };
                gwin_get_model_pid((uint32_t)&product);

                GWIN_DEBUG("model:              %s", product.model);
                GWIN_DEBUG("pid:                %d", product.pid);
                GWIN_DEBUG("version:            %s", product.version);
                GWIN_DEBUG("miot_security_siid: %d", product.miot_security_siid);

                len = strlen((char *)product.model);
                memcpy(&payload_data[payload_len], product.model, len);
                payload_len += len;
                payload_data[payload_len] = GWIN_PROT_MODEL_PID_SEP_SYMBOL;
                payload_len += 1;

                memset(str, 0x00, sizeof(str));
                snprintf((char *)str, sizeof(str), "%d", product.pid);
                len = strlen((char *)str);
                memcpy(&payload_data[payload_len], str, len);
                payload_len += len;
                payload_data[payload_len] = GWIN_PROT_MODEL_PID_SEP_SYMBOL;
                payload_len += 1;

                len = strlen((char *)product.version);
                memcpy(&payload_data[payload_len], product.version, len);
                payload_len += len;
                payload_data[payload_len] = GWIN_PROT_MODEL_PID_SEP_SYMBOL;
                payload_len += 1;

                memset(str, 0x00, sizeof(str));
                snprintf((char *)str, sizeof(str), "%d", product.miot_security_siid);
                len = strlen((char *)str);
                memcpy(&payload_data[payload_len], str, len);
                payload_len += len;
            }
            break;

        case GWIN_PROT_CMD_BUILD_TIME:
            {
                find = 1;
                uint8_t len = strlen(__DATE__ " " __TIME__);
                memcpy(&payload_data[payload_len], __DATE__ " " __TIME__, len);
                payload_len += len;
            }
            break;

        case GWIN_PROT_CMD_FW_NAME_TOTAL:
            {
                find = 1;
                uint8_t len = strlen(GWIN_FW_NAME_TOTAL);
                memcpy(&payload_data[payload_len], GWIN_FW_NAME_TOTAL, len);
                payload_len += len;
            }
            break;

        case GWIN_PROT_CMD_FW_VERSION:
            {
                find = 1;
                uint8_t len = strlen(GWIN_VERSION);
                memcpy(&payload_data[payload_len], GWIN_VERSION, len);
                payload_len += len;
            }
            break;

        #if (GWIN_PROT_TYPE == GWIN_PROT_TYPE_WIFI || GWIN_PROT_TYPE == GWIN_PROT_TYPE_MESH)
        case GWIN_PROT_CMD_UTC:
            {
                find = 1;
                uint32_t timestamp = gwin_get_utc_time() + gwin_get_timezone() * 3600;
                gwin_utc_clock_datetime_t datetime = { 0x00 };
                gwin_utc_clock_timestamp_to_datetime(&timestamp, &datetime);
                datetime.year = HL_SWAP_U16(datetime.year);
                memcpy(&payload_data[payload_len], &datetime.year, sizeof(datetime.year));
                payload_len += sizeof(datetime.year);
                payload_data[payload_len] = datetime.month;
                payload_len += 1;
                payload_data[payload_len] = datetime.day;
                payload_len += 1;
                payload_data[payload_len] = datetime.week + 1;      // 运算库：0~6，周一是0；串口协议：1~7，周一是1
                payload_len += 1;
                payload_data[payload_len] = datetime.hour;
                payload_len += 1;
                payload_data[payload_len] = datetime.minute;
                payload_len += 1;
                payload_data[payload_len] = datetime.second;
                payload_len += 1;
            }
            break;
        #endif

        #if (GWIN_PROT_TYPE == GWIN_PROT_TYPE_MESH)
        case GWIN_PROT_CMD_WEATHER:
            {
                find = 1;
                uint16_t weather = gwin_get_weather();
                weather = HL_SWAP_U16(weather);
                memcpy(&payload_data[payload_len], &weather, sizeof(weather));
                payload_len += sizeof(weather);
            }
            break;
        #endif

        default:
            break;
    }

    if (find)
    {
        total_len = gwin_protocol_pack_to_mcu(buf, cmd, payload_len);

        gwin_protocol_send_to_mcu(buf, total_len);
    }
}


/**
 * @brief 广播包内容（接收）
 *
 */
static void gwin_protocol_adv_recv(uint8_t way, uint8_t *data, uint16_t len)
{
    uint8_t cmd = 0;
    uint8_t buf[GWIN_UART_MAX_LEN] = {0x00};
    uint8_t *payload_data = &buf[GWIN_PROT_INDEX_PAYLOAD_DATA];
    uint16_t payload_len = 0;
    uint16_t total_len = 0;

    switch(way)
    {
      case PROTOCOL_TASK_DATA_WAY_REMOTE:
          cmd = GWIN_PROT_CMD_ADV_RECV;
      break;

      case PROTOCOL_TASK_DATA_WAY_LESHI_REMOTE:
          cmd = GWIN_PROT_CMD_ADV_RECV_LE_SHI;
      break;

      case PROTOCOL_TASK_DATA_WAY_PINGTUOXIONG_REMOTE:
          cmd = GWIN_PROT_CMD_ADV_RECV_PTX;
      break;

      default:
          break;
    }
    // 11 07 01 01 22 22 22 12 0C 00 D9 49 5F 79 B5 85 A2 5C
    // 只从 01 01 开始，所以 -2
    data += 2;
    len -= 2;
    memcpy(&payload_data[payload_len], data, len);
    payload_len += len;

    total_len = gwin_protocol_pack_to_mcu(buf, cmd, payload_len);
    gwin_protocol_send_to_mcu(buf, total_len);
}

/**
 * @brief 数据通讯 MCU发送到云端
 */
static void gwin_protocol_spec_to_cloud(uint8_t cmd, uint8_t *data, uint16_t len)
{
    uint8_t result = GWIN_PROT_ACK_FAIL;
    uint16_t pos = 0;
    uint8_t change = 0;

    gwin_spec_unit_t spec_uint = { 0x00 };
    while (pos + GWIN_SPEC_UNIT_LEN <= len)
    {
        memcpy(&spec_uint.siid, &data[pos], sizeof(spec_uint.siid));
        pos += sizeof(spec_uint.siid);
        memcpy(&spec_uint.ea_iid, &data[pos], sizeof(spec_uint.ea_iid));
        pos += sizeof(spec_uint.ea_iid);
        memcpy(&spec_uint.piid, &data[pos], sizeof(spec_uint.piid));
        pos += sizeof(spec_uint.piid);
        memcpy(&spec_uint.data_type, &data[pos], sizeof(spec_uint.data_type));
        pos += sizeof(spec_uint.data_type);
        memcpy(&spec_uint.value, &data[pos], sizeof(spec_uint.value));
        pos += sizeof(spec_uint.value);

        spec_uint.siid = HL_SWAP_U16(spec_uint.siid);
        spec_uint.ea_iid = HL_SWAP_U16(spec_uint.ea_iid);
        spec_uint.piid = HL_SWAP_U16(spec_uint.piid);
        spec_uint.value = HL_SWAP_U32(spec_uint.value);
        if (spec_uint.data_type == DATA_TYPE_NONE
                || spec_uint.data_type == DATA_TYPE_BOOL
                || spec_uint.data_type == DATA_TYPE_U8
                || spec_uint.data_type == DATA_TYPE_U16
                || spec_uint.data_type == DATA_TYPE_U32
                || spec_uint.data_type == DATA_TYPE_I8
                || spec_uint.data_type == DATA_TYPE_I16
                || spec_uint.data_type == DATA_TYPE_I32
                || spec_uint.data_type == DATA_TYPE_F32)
        {
            // 事件
            if (spec_uint.ea_iid != GWIN_SPEC_PEA_IID_NONE)
            {
                gwin_spec_event_occurred(spec_uint.siid, spec_uint.ea_iid, spec_uint.piid, spec_uint.data_type, spec_uint.value);
                result = GWIN_PROT_ACK_SUCCESS;
            }
            // 属性
            else
            {
                if (spec_uint.data_type != DATA_TYPE_NONE)
                {
                    spec_uint.change = 1;
                    gwin_set_spec((uint32_t)&spec_uint);

                    change = 1;

                    result = GWIN_PROT_ACK_SUCCESS;
                }
            }
        }
    }

    if (change)
    {
        gwin_set_spec_save((uint32_t)NULL);
    }

    gwin_protocol_ack(cmd, result);
}

/**
 * @brief 数据通讯 云端发送到MCU
 */
static void gwin_protocol_spec_to_mcu(uint8_t *data, uint16_t len)
{
    GWIN_DEBUG("");

    uint8_t cmd = GWIN_PROT_CMD_SPEC;
    uint8_t buf[GWIN_UART_MAX_LEN] = { 0x00 };
    uint8_t *payload_data = &buf[GWIN_PROT_INDEX_PAYLOAD_DATA];
    uint16_t payload_len = 0;
    uint16_t total_len = 0;

    gwin_spec_unit_t spec_uint = { 0x00 };
    memcpy(&spec_uint, data, sizeof(gwin_spec_unit_t));
    if (spec_uint.data_type == DATA_TYPE_NONE
            || spec_uint.data_type == DATA_TYPE_BOOL
            || spec_uint.data_type == DATA_TYPE_U8
            || spec_uint.data_type == DATA_TYPE_U16
            || spec_uint.data_type == DATA_TYPE_U32
            || spec_uint.data_type == DATA_TYPE_I8
            || spec_uint.data_type == DATA_TYPE_I16
            || spec_uint.data_type == DATA_TYPE_I32
            || spec_uint.data_type == DATA_TYPE_F32)
    {
        // 动作
        if (spec_uint.piid == GWIN_SPEC_PEA_IID_NONE)
        {

        }
        // 属性
        else
        {
            if (spec_uint.data_type != DATA_TYPE_NONE)
            {
                // 后台下发，保存spec
                #if (GWIN_PROT_TYPE == GWIN_PROT_TYPE_WIFI)
                // wifi模块，以设备端为准，后台下发任何属性点，必须设备上报
                spec_uint.change = 1;
                #else
                spec_uint.change = 0;
                #endif
                gwin_set_spec((uint32_t)&spec_uint);
                gwin_set_spec_save((uint32_t)NULL);
            }
        }

        spec_uint.siid = HL_SWAP_U16(spec_uint.siid);
        spec_uint.ea_iid = HL_SWAP_U16(spec_uint.ea_iid);
        spec_uint.piid = HL_SWAP_U16(spec_uint.piid);
        spec_uint.value = HL_SWAP_U32(spec_uint.value);

        memcpy(&payload_data[payload_len], &spec_uint.siid, sizeof(spec_uint.siid));
        payload_len += sizeof(spec_uint.siid);
        memcpy(&payload_data[payload_len], &spec_uint.ea_iid, sizeof(spec_uint.ea_iid));
        payload_len += sizeof(spec_uint.ea_iid);
        memcpy(&payload_data[payload_len], &spec_uint.piid, sizeof(spec_uint.piid));
        payload_len += sizeof(spec_uint.piid);
        memcpy(&payload_data[payload_len], &spec_uint.data_type, sizeof(spec_uint.data_type));
        payload_len += sizeof(spec_uint.data_type);
        memcpy(&payload_data[payload_len], &spec_uint.value, sizeof(spec_uint.value));
        payload_len += sizeof(spec_uint.value);

        total_len = gwin_protocol_pack_to_mcu(buf, cmd, payload_len);
        gwin_protocol_send_to_mcu(buf, total_len);
    }
}

/**
 * @brief 数据通讯 字符串 MCU发送到云端
 */
static void gwin_protocol_spec_string_to_cloud(uint8_t cmd, uint8_t *data, uint16_t len)
{
    uint8_t result = GWIN_PROT_ACK_FAIL;

    #if (GWIN_PROT_TYPE == GWIN_PROT_TYPE_WIFI || GWIN_PROT_TYPE == GWIN_PROT_TYPE_BLE)

    uint16_t pos = 0;
    uint8_t change = 0;

    gwin_spec_unit_t spec_uint = { 0x00 };
    memcpy(&spec_uint.siid, &data[pos], sizeof(spec_uint.siid));
    pos += sizeof(spec_uint.siid);
    memcpy(&spec_uint.ea_iid, &data[pos], sizeof(spec_uint.ea_iid));
    pos += sizeof(spec_uint.ea_iid);
    memcpy(&spec_uint.piid, &data[pos], sizeof(spec_uint.piid));
    pos += sizeof(spec_uint.piid);
    memcpy(&spec_uint.data_type, &data[pos], sizeof(spec_uint.data_type));
    pos += sizeof(spec_uint.data_type);
    spec_uint.len = GWIN_SPEC_STR_LEN(len);
    spec_uint.value = (uint32_t)&data[pos];

    spec_uint.siid = HL_SWAP_U16(spec_uint.siid);
    spec_uint.ea_iid = HL_SWAP_U16(spec_uint.ea_iid);
    spec_uint.piid = HL_SWAP_U16(spec_uint.piid);

    if (spec_uint.data_type == DATA_TYPE_STRING)
    {
        // 事件
        if (spec_uint.ea_iid != GWIN_SPEC_PEA_IID_NONE)
        {

        }
        // 属性
        else
        {
            if (spec_uint.data_type != DATA_TYPE_NONE)
            {
                spec_uint.change = 1;
                gwin_set_spec((uint32_t)&spec_uint);

                change = 1;

                result = GWIN_PROT_ACK_SUCCESS;
            }
        }
    }

    if (change)
    {
        gwin_set_spec_save((uint32_t)NULL);
    }

    #endif

    gwin_protocol_ack(cmd, result);
}

/**
 * @brief 数据通讯 字符串 云端发送到MCU
 */
static void gwin_protocol_spec_string_to_mcu(uint8_t *data, uint16_t len)
{
    GWIN_DEBUG("");

    #if (GWIN_PROT_TYPE == GWIN_PROT_TYPE_WIFI || GWIN_PROT_TYPE == GWIN_PROT_TYPE_BLE)

    uint8_t cmd = GWIN_PROT_CMD_SPEC_STRING;
    uint8_t buf[GWIN_UART_MAX_LEN] = { 0x00 };
    uint8_t *payload_data = &buf[GWIN_PROT_INDEX_PAYLOAD_DATA];
    uint16_t payload_len = 0;
    uint16_t total_len = 0;

    gwin_spec_unit_t spec_uint = { 0x00 };
    memcpy(&spec_uint, data, sizeof(gwin_spec_unit_t));

    // 后台下发，保存spec
    #if (GWIN_PROT_TYPE == GWIN_PROT_TYPE_WIFI)
    // wifi模块，以设备端为准，后台下发任何属性点，必须设备上报
    spec_uint.change = 1;
    #else
    spec_uint.change = 0;
    #endif
    gwin_set_spec((uint32_t)&spec_uint);
    gwin_set_spec_save((uint32_t)NULL);

    spec_uint.siid = HL_SWAP_U16(spec_uint.siid);
    spec_uint.ea_iid = HL_SWAP_U16(spec_uint.ea_iid);
    spec_uint.piid = HL_SWAP_U16(spec_uint.piid);

    memcpy(&payload_data[payload_len], &spec_uint.siid, sizeof(spec_uint.siid));
    payload_len += sizeof(spec_uint.siid);
    memcpy(&payload_data[payload_len], &spec_uint.ea_iid, sizeof(spec_uint.ea_iid));
    payload_len += sizeof(spec_uint.ea_iid);
    memcpy(&payload_data[payload_len], &spec_uint.piid, sizeof(spec_uint.piid));
    payload_len += sizeof(spec_uint.piid);
    memcpy(&payload_data[payload_len], &spec_uint.data_type, sizeof(spec_uint.data_type));
    payload_len += sizeof(spec_uint.data_type);
    memcpy(&payload_data[payload_len], (const char *)spec_uint.value, spec_uint.len);
    payload_len += spec_uint.len;

    total_len = gwin_protocol_pack_to_mcu(buf, cmd, payload_len);
    gwin_protocol_send_to_mcu(buf, total_len);

    #endif
}

/**
 * @brief 系统状态
 */
static void gwin_protocol_sys_state(uint8_t cmd, uint8_t *data, uint16_t len)
{
    GWIN_DEBUG("");

    gwin_protocol_send_cmd_to_mcu(cmd);
}

/**
 * @brief 低功耗
 */
static void gwin_protocol_low_pwr(uint8_t cmd, uint8_t *data, uint16_t len)
{
    GWIN_DEBUG("");

    #if (GWIN_PROT_TYPE == GWIN_PROT_TYPE_WIFI || GWIN_PROT_TYPE == GWIN_PROT_TYPE_MESH)
    uint8_t result = GWIN_PROT_ACK_FAIL;
    #elif (GWIN_PROT_TYPE == GWIN_PROT_TYPE_BLE)
    uint8_t result = GWIN_PROT_ACK_SUCCESS;
    #endif

    gwin_protocol_ack(cmd, result);

    #if (GWIN_PROT_TYPE == GWIN_PROT_TYPE_BLE)
    gwin_main_extern_action(MAIN_TASK_MSG_EX_ACT_SUBTYPE_LOW_PWR);
    #endif
}

/**
 * @brief model、pid 设置
 */
static void gwin_protocol_model_pid_set(uint8_t cmd, uint8_t *data, uint16_t len)
{
    uint8_t result = GWIN_PROT_ACK_FAIL;

    uint8_t change_to_network_reset = 0;
    uint8_t is_change = 0;
    uint8_t section_start[GWIN_PROT_MODEL_PID_SEC_INDEX_MAX + 1] = { 0x00 };
    uint8_t section_len[GWIN_PROT_MODEL_PID_SEC_INDEX_MAX + 1] = { 0x00 };
    uint8_t section_index = 0;

    // 开始
    section_start[section_index++] = 0;
    // 中间
    for (uint8_t i = 0; i < len; i++)
    {
        if (GWIN_PROT_MODEL_PID_SEP_SYMBOL == data[i])
        {
            if (section_index < GWIN_PROT_MODEL_PID_SEC_INDEX_MAX)
            {
                i += 1;                         // +1跳过分隔符
                section_start[section_index++] = i;
            }
        }
    }
    // 结束
    section_start[section_index++] = len + 1;   // +1补充分隔符

    if (section_index >= GWIN_PROT_MODEL_PID_SEC_INDEX_MIN + 1)
    {
        // 长度解析
        for (uint8_t i = 0; i < section_index - 1; i++)
        {
            section_len[i] = section_start[i + 1] - section_start[i];
            if (section_len[i] > 0)
            {
                section_len[i] -= 1;            // -1跳过分隔符
            }
        }
        // 数据域内容解析
        char str[48] = { 0x00 };
        uint8_t *model = NULL, *pid = NULL, *version = NULL, *miot_security_siid = NULL;
        uint8_t model_len = 0, pid_len = 0, version_len = 0, miot_security_siid_len = 0;
        int32_t temp_num = 0;
        uint16_t pid_num = 0;
        uint16_t version_num = 0;
        uint16_t miot_security_siid_num = 0;
        // model
        model = &data[section_start[GWIN_PROT_MODEL_PID_SEC_INDEX_MODEL]];
        model_len = section_len[GWIN_PROT_MODEL_PID_SEC_INDEX_MODEL];
        // pid
        pid = &data[section_start[GWIN_PROT_MODEL_PID_SEC_INDEX_PID]];
        pid_len = section_len[GWIN_PROT_MODEL_PID_SEC_INDEX_PID];
        memset(str, 0x00, sizeof (str));
        memcpy(str, pid, MIN(pid_len, sizeof (str) - 1));
        temp_num = atoi(str);
        if (temp_num > 0)
        {
            pid_num = temp_num;
        }
        else
        {
            pid = NULL;
            pid_len = 0;
            pid_num = 0;
        }
        // version
        temp_num = 0;
        if (section_index >= GWIN_PROT_MODEL_PID_SEC_INDEX_VERSION + 1)
        {
            if (GWIN_PROT_MODEL_PID_DEFAULT_SYMBOL != data[section_start[GWIN_PROT_MODEL_PID_SEC_INDEX_VERSION]])
            {
                version = &data[section_start[GWIN_PROT_MODEL_PID_SEC_INDEX_VERSION]];
                version_len = section_len[GWIN_PROT_MODEL_PID_SEC_INDEX_VERSION];
                memset(str, 0x00, sizeof (str));
                memcpy(str, version, MIN(version_len, sizeof (str) - 1));
                temp_num = atoi(str);
            }
        }
        if (temp_num > 0)
        {
            version_num = temp_num;
        }
        else
        {
            version = NULL;
            version_len = 0;
            version_num = 0;
        }
        // miot_security_siid
        temp_num = 0;
        if (section_index >= GWIN_PROT_MODEL_PID_SEC_INDEX_MIOT_SECURITY_SIID + 1)
        {
            if (GWIN_PROT_MODEL_PID_DEFAULT_SYMBOL != data[section_start[GWIN_PROT_MODEL_PID_SEC_INDEX_MIOT_SECURITY_SIID]])
            {
                miot_security_siid = &data[section_start[GWIN_PROT_MODEL_PID_SEC_INDEX_MIOT_SECURITY_SIID]];
                miot_security_siid_len = section_len[GWIN_PROT_MODEL_PID_SEC_INDEX_MIOT_SECURITY_SIID];
                memset(str, 0x00, sizeof (str));
                memcpy(str, miot_security_siid, MIN(miot_security_siid_len, sizeof (str) - 1));
                temp_num = atoi(str);
            }
        }
        if (temp_num > 0)
        {
            miot_security_siid_num = temp_num;
        }
        else
        {
            miot_security_siid = NULL;
            miot_security_siid_len = 0;
            miot_security_siid_num = 0;
        }

        if (pid_num > 0)
        {
            system_param_product_t product = { 0x00 };
            system_param_product_t last_product = { 0x00 };
            gwin_get_model_pid((uint32_t)&last_product);
            memcpy(&product, &last_product, sizeof(system_param_product_t));
            model_len = MIN(model_len, BLE_NAME_MAX_LEN);
            memset(product.model, 0x00, sizeof(product.model));
            memcpy(product.model, model, model_len);
            product.pid = pid_num;
            if (!last_product.lock)
            {
                result = GWIN_PROT_ACK_SUCCESS;
                if (memcmp(product.model, last_product.model, sizeof(product.model)) != 0 || product.pid != last_product.pid)
                {
                    is_change = 1;
                    change_to_network_reset = 1;
                }
            }
            else
            {
                memcpy(product.model, last_product.model, strlen(last_product.model));
                product.pid = last_product.pid;
            }
            if (version != NULL)
            {
                product.version_custom_enable = 1;
                product.version_num = version_num;
                version_len = MIN(version_len, VERSION_LEN);
                memset(product.version, 0x00, sizeof(product.version));
                memcpy(product.version, version, version_len);
                if (memcmp(product.version, last_product.version, sizeof(product.version)) != 0 || product.version_num != last_product.version_num)
                {
                    is_change = 1;
                    change_to_network_reset = 1;
                }
            }
            if (miot_security_siid != NULL)
            {
                product.miot_security_siid = miot_security_siid_num;
                if (product.miot_security_siid != last_product.miot_security_siid)
                {
                    is_change = 1;
                    #if GWIN_PROT_SPEC_SECURITY
                    gwin_set_spec_security(product.miot_security_siid);
                    #endif
                }
            }

            GWIN_DEBUG("model:              %s", product.model);
            GWIN_DEBUG("pid:                %d", product.pid);
            GWIN_DEBUG("version:            %s", product.version);
            GWIN_DEBUG("miot_security_siid: %d", product.miot_security_siid);

            if (is_change)
            {
                gwin_set_model_pid((uint32_t)&product);
            }

            result = GWIN_PROT_ACK_SUCCESS;
        }
    }

    gwin_protocol_ack(cmd, result);

    if (change_to_network_reset)
    {
        gwin_main_extern_action(MAIN_TASK_MSG_EX_ACT_SUBTYPE_NET_RESET);
    }
    else
    {
        gwin_main_extern_action(MAIN_TASK_MSG_EX_ACT_SUBTYPE_FUNC_START);
    }
}

/**
 * @brief model、pid 获取
 */
static void gwin_protocol_model_pid_get(uint8_t cmd, uint8_t *data, uint16_t len)
{
    GWIN_DEBUG("");

    gwin_protocol_send_cmd_to_mcu(cmd);
}

/**
 * @brief 验证码
 */
static void gwin_protocol_verification_code(uint8_t cmd, uint8_t *data, uint16_t len)
{
    GWIN_DEBUG("");

    uint8_t result = GWIN_PROT_ACK_SUCCESS;

    // 保险柜特殊需求：输入验证码，比如，验证码是：123456，则命令是：
    // 55 AA 45 00 06 01 02 03 04 05 06
    #define OOB_LEN         6
    uint8_t ret = 0;
    if (len >= OOB_LEN)
    {
        uint8_t oob[OOB_LEN] = { 0x00 };
        memcpy(oob, &data[0], sizeof(oob));
        ret = 1;
        for (uint8_t i = 0; i < sizeof(oob); i++)
        {
            if (oob[i] > 9)
            {
                ret = 0;
                break;
            }
            oob[i] = '0' + oob[i];
        }
        if (ret)
        {
            mi_schd_oob_rsp(oob, 6);
        }
    }
    if (!ret)
    {
        result = GWIN_PROT_ACK_FAIL;
    }

    gwin_protocol_ack(cmd, result);
}

/**
 * @brief 激活配对
 */
static void gwin_protocol_active_pair(uint8_t cmd, uint8_t *data, uint16_t len)
{
    GWIN_DEBUG("");

    uint8_t result = GWIN_PROT_ACK_SUCCESS;

    gwin_main_extern_action_with_param(MAIN_TASK_MSG_EX_ACT_SUBTYPE_ACTIVE_PAIR, data[0]);

    gwin_protocol_ack(cmd, result);
}

/**
 * @brief 设置配对模式
 */
static void gwin_protocol_pair_mode(uint8_t cmd, uint8_t *data, uint16_t len)
{
    GWIN_DEBUG("");

    
    uint8_t result = GWIN_PROT_ACK_SUCCESS;

    gwin_main_extern_action_with_param(MAIN_TASK_MSG_EX_ACT_SUBTYPE_SET_PAIR_MODE,data[0]);

    gwin_protocol_ack(cmd, result);
}

/**
 * @brief 网络
 */
static void gwin_protocol_network(uint8_t cmd, uint8_t *data, uint16_t len)
{
    GWIN_DEBUG("");

    uint8_t result = GWIN_PROT_ACK_SUCCESS;

    uint32_t network_timeout = 0;
    switch (data[0])
    {
        case GWIN_PROT_NETWORK_TIMEOUT_MINUTE_2:
            network_timeout = 2 * 60 * 1000;
            break;
        case GWIN_PROT_NETWORK_TIMEOUT_MINUTE_10:
            network_timeout = 10 * 60 * 1000;
            break;
        case GWIN_PROT_NETWORK_TIMEOUT_MINUTE_30:
            network_timeout = 30 * 60 * 1000;
            break;
    }
    if (network_timeout > 0)
    {
        gwin_set_network_timeout(network_timeout);
    }
    gwin_main_extern_action(MAIN_TASK_MSG_EX_ACT_SUBTYPE_NET_RESET);

    gwin_protocol_ack(cmd, result);
}

/**
 * @brief 查询命令
 */
static void gwin_protocol_query(uint8_t cmd, uint8_t *data, uint16_t len)
{
    gwin_protocol_send_cmd_to_mcu(data[0]);
}

/**
 * @brief 查询固件编译时间
 */
static void gwin_protocol_build_time(uint8_t cmd, uint8_t *data, uint16_t len)
{
    GWIN_DEBUG("");

    gwin_protocol_send_cmd_to_mcu(cmd);
}

/**
 * @brief 查询完整固件名
 */
static void gwin_protocol_fw_name_total(uint8_t cmd, uint8_t *data, uint16_t len)
{
    GWIN_DEBUG("");

    gwin_protocol_send_cmd_to_mcu(cmd);
}

/**
 * @brief 查询芯片固件版本
 */
static void gwin_protocol_fw_version(uint8_t cmd, uint8_t *data, uint16_t len)
{
    GWIN_DEBUG("");

    gwin_protocol_send_cmd_to_mcu(cmd);
}

/**
 * @brief 查询模组时间
 */
static void gwin_protocol_utc(uint8_t cmd, uint8_t *data, uint16_t len)
{
    GWIN_DEBUG("");

    gwin_protocol_send_cmd_to_mcu(cmd);
}

/**
 * @brief 查询天气数据
 */
static void gwin_protocol_weather(uint8_t cmd, uint8_t *data, uint16_t len)
{
    GWIN_DEBUG("");

    gwin_protocol_send_cmd_to_mcu(cmd);
}

/**
 * @brief 强制复位所有参数（研发预留接口，防止错误，直接响应）
 */
static void gwin_protocol_reset_all_force(uint8_t cmd, uint8_t *data, uint16_t len)
{
    GWIN_DEBUG("");

    #define RESET_ALL_FORCE_CMD         "reset_all_force"
    // 转换后的命令：55 AA E0 00 0F 72 65 73 65 74 5F 61 6C 6C 5F 66 6F 72 63 65

    uint8_t cmd_str_len = strlen(RESET_ALL_FORCE_CMD);
    cmd_str_len = MAX(cmd_str_len, len);
    if (memcmp(data, RESET_ALL_FORCE_CMD, cmd_str_len) == 0)
    {
        gwin_main_extern_action(MAIN_TASK_MSG_EX_ACT_SUBTYPE_RESET_ALL_FORCE);
    }
}





/*----------- 数据交互 MCU -----------*/
/**
 * @brief 发送数据
 */
static void gwin_protocol_send_to_mcu(uint8_t *data, uint16_t len)
{
    len = gwin_fifo_write(&protocol_fifo_tx_mcu.fifo, data, len);
    gwin_fifo_write(&protocol_list_tx_mcu.fifo, (uint8_t *)&len, sizeof(len));

    if (!_os_timer_is_active(uart_tx))
    {
        gwin_wakeup_extern_set_state(1);

//        gwin_protocol_uart_tx_callback(NULL);
        _os_timer_start(uart_tx, 0);
    }
}

/**
 * @brief 接收数据
 *
 * @return 0:成功；
 *          长度错误：-1：少于最小；    -2：少于应接接收的长度；
 *          协议格式：-3：协议头错误；
 *          协议内容：-4：协议未定义；
 */
static int8_t gwin_protocol_recv_from_mcu(uint8_t *data, uint16_t len)
{
    uint16_t head;
    uint8_t cmd;
    uint16_t payload_len;
    uint16_t total_len;
    uint8_t find;

RECV_FROM_MCU_NEXT_PACKAGE:

    if (len < GWIN_PROT_MIN_LEN)
    {
        return -1;
    }

    memcpy(&payload_len, &data[GWIN_PROT_INDEX_PAYLOAD_LEN_1], sizeof(payload_len));
    payload_len = HL_SWAP_U16(payload_len);
    total_len = payload_len + GWIN_PROT_MIN_LEN;
    if (len < total_len)
    {
        return -2;
    }

    memcpy(&head, &data[GWIN_PROT_INDEX_HEAD_1], sizeof(head));
    head = HL_SWAP_U16(head);
    if (head != GWIN_PROT_HEAD_RECV)
    {
        return -3;
    }

    find = 0;
    cmd = data[GWIN_PROT_INDEX_CMD];
    for (uint8_t i = 0; i < gwin_protocol_cmd_map_cnt; i++)
    {
        if (cmd == gwin_protocol_cmd_map[i].cmd && gwin_protocol_cmd_map[i].func != NULL)
        {
            find = 1;
            GWIN_DEBUG("cmd = %x", cmd);
            gwin_protocol_data_recv(PROTOCOL_TASK_DATA_WAY_MCU, data, len);
            break;
        }
    }

    if (!find)
    {
        return -4;
    }
    else
    {
        // 多包数据粘包，连续解析下一包
        if (len > total_len)
        {
            data = &data[total_len];
            len -= total_len;
            goto RECV_FROM_MCU_NEXT_PACKAGE;
        }

        return 0;
    }
}


/**
 * @brief 打包数据
 */
static uint16_t gwin_protocol_pack_to_mcu(uint8_t *data, uint8_t cmd, uint16_t payload_len)
{
    uint16_t head = HL_SWAP_U16(GWIN_PROT_HEAD_SEND);
    uint16_t tmp_len = HL_SWAP_U16(payload_len);
    memcpy(&data[GWIN_PROT_INDEX_HEAD_1], &head, sizeof(head));
    data[GWIN_PROT_INDEX_CMD] = cmd;
    memcpy(&data[GWIN_PROT_INDEX_PAYLOAD_LEN_1], &tmp_len, sizeof(tmp_len));

    return (payload_len + GWIN_PROT_MIN_LEN);
}

/**
 * @brief 解析数据
 */
static void gwin_protocol_parse_from_mcu(uint8_t *data, uint16_t len)
{
    uint8_t cmd = data[GWIN_PROT_INDEX_CMD];
    uint8_t *payload_data = &data[GWIN_PROT_INDEX_PAYLOAD_DATA];
    uint16_t payload_len = 0;
    memcpy(&payload_len, &data[GWIN_PROT_INDEX_PAYLOAD_LEN_1], sizeof(payload_len));
    payload_len = HL_SWAP_U16(payload_len);

    for (uint8_t i = 0; i < gwin_protocol_cmd_map_cnt; i++)
    {
        if (cmd == gwin_protocol_cmd_map[i].cmd && gwin_protocol_cmd_map[i].func != NULL)
        {
            GWIN_DEBUG("cmd = %x", cmd);
            gwin_protocol_cmd_map[i].func(cmd, payload_data, payload_len);
            break;
        }
    }
}


/*----------- 数据交互 ble(mesh) -----------*/
/**
 * @brief 解析数据
 */
static void gwin_protocol_parse_from_ble(uint8_t way, uint8_t *data, uint16_t len)
{
    //GWIN_DEBUG("way = %d, len = %d", way, len);

    switch(way)
    {
        case PROTOCOL_TASK_DATA_WAY_REMOTE:
        case PROTOCOL_TASK_DATA_WAY_LESHI_REMOTE:
        case PROTOCOL_TASK_DATA_WAY_PINGTUOXIONG_REMOTE:
            gwin_protocol_adv_recv(way, data, len);
            break;

        case PROTOCOL_TASK_DATA_WAY_SPEC_SET:
        case PROTOCOL_TASK_DATA_WAY_SPEC_ACT:
            {
                gwin_spec_unit_t *spec_uint = (gwin_spec_unit_t *)data;
                if (spec_uint->data_type == DATA_TYPE_STRING)
                {
                    gwin_protocol_spec_string_to_mcu(data, len);
                }
                else
                {
                    gwin_protocol_spec_to_mcu(data, len);
                }
            }
            break;

        default:
            return;
    }
}





/*----------- 任务 -----------*/
/**
 * @brief 接收数据
 */
void gwin_protocol_data_recv(uint8_t way, uint8_t *data, uint16_t len)
{
    gwin_protocol_task_msg_t msg = { 0 };
    msg.type = PROTOCOL_TASK_MSG_TYPE_RECV;
    msg.subtype = way;
    msg.data = data;
    msg.len = len;
    #if GWIN_PROT_RX_IRQ
    if (msg.subtype == PROTOCOL_TASK_DATA_WAY_MCU)
    {
        // 串口接收是从中断过来的，要特殊处理，消息放到main去做
        len = gwin_fifo_write(&protocol_fifo_rx_mcu.fifo, data, msg.len);
        gwin_fifo_write(&protocol_list_rx_mcu.fifo, (uint8_t *)&len, sizeof(len));
        #if GWIN_PROT_RX_IRQ_RTOS_QUEUE     // 减少定时器唤醒，串口接收用实时系统消息队列分离中断处理
        gwin_protocol_uart_rx_callback(NULL);
        #endif
    }
    else
    {
        gwin_send_msg_to_protocol_task(&msg);
    }
    #else
    gwin_send_msg_to_protocol_task(&msg);
    #endif
}

/**
 * @brief 发送数据
 */
void gwin_protocol_data_send_mcu(uint32_t type)
{
    gwin_protocol_task_msg_t msg = { 0 };
    msg.type = PROTOCOL_TASK_MSG_TYPE_SEND;
    msg.subtype = PROTOCOL_TASK_DATA_WAY_MCU;
    msg.param = type;
    gwin_send_msg_to_protocol_task(&msg);
}


/**
 * @brief 定时器消息处理
 */
static void gwin_protocol_task_timer_msg_handle(gwin_protocol_task_msg_t *msg)
{
    uint16_t subtype = msg->subtype;

    switch(subtype)
    {
        #if GWIN_PROT_RX_IRQ
        case PROTOCOL_TASK_MSG_TIMER_SUBTYPE_UART_RX:
            {
                if (gwin_fifo_length(&protocol_list_rx_mcu.fifo))
                {
                    uint8_t data[GWIN_UART_MAX_LEN] = { 0x00 };
                    uint16_t len = 0;
                    gwin_fifo_read(&protocol_list_rx_mcu.fifo, (uint8_t *)&len, sizeof(len));
                    gwin_fifo_read(&protocol_fifo_rx_mcu.fifo, (uint8_t *)&data, len);

                    #if (GWIN_PROT_TYPE == GWIN_PROT_TYPE_BLE)
                    gwin_main_extern_action(MAIN_TASK_MSG_EX_ACT_SUBTYPE_WAKEUP);
                    #endif
                    gwin_protocol_parse_from_mcu(data, len);
                    gwin_main_extern_action(MAIN_TASK_MSG_EX_ACT_SUBTYPE_FUNC_START);
                }
            }
            break;
        #endif

        case PROTOCOL_TASK_MSG_TIMER_SUBTYPE_UART_TX:
            {
                if (gwin_fifo_length(&protocol_list_tx_mcu.fifo))
                {
                    uint8_t data[GWIN_UART_MAX_LEN] = { 0x00 };
                    uint16_t len = 0;
                    // 读
                    gwin_fifo_read(&protocol_list_tx_mcu.fifo, (uint8_t *)&len, sizeof(len));
                    gwin_fifo_read(&protocol_fifo_tx_mcu.fifo, data, len);
                    // 发送
                    gwin_uart_send((const uint8_t *)data, len);
                    // 循环发送
                    _os_timer_start(uart_tx, 0);
                }
            }
            break;

        default:
            GWIN_DEBUG("Error : subtype of timer msg is unknown %d !!!", subtype);
            break;
    }
}

/**
 * @brief 接收消息处理
 */
static void gwin_protocol_task_recv_msg_handle(gwin_protocol_task_msg_t *msg)
{
    uint16_t subtype = msg->subtype;
    switch(subtype)
    {
        #if !GWIN_PROT_RX_IRQ
        case PROTOCOL_TASK_DATA_WAY_MCU:
            {
                gwin_protocol_parse_from_mcu(msg->data, msg->len);
            }
            break;
        #endif

        #if (GWIN_PROT_TYPE == GWIN_PROT_TYPE_WIFI || GWIN_PROT_TYPE == GWIN_PROT_TYPE_MESH)
        case PROTOCOL_TASK_DATA_WAY_REMOTE:
        case PROTOCOL_TASK_DATA_WAY_LESHI_REMOTE:
        case PROTOCOL_TASK_DATA_WAY_PINGTUOXIONG_REMOTE:
        #endif
        case PROTOCOL_TASK_DATA_WAY_SPEC_SET:
        case PROTOCOL_TASK_DATA_WAY_SPEC_ACT:
            {
                gwin_protocol_parse_from_ble(subtype, msg->data, msg->len);
            }
            break;

        default:
            break;
    }
}

/**
 * @brief 发送消息处理
 */
static void gwin_protocol_task_send_msg_handle(gwin_protocol_task_msg_t *msg)
{
    uint16_t subtype = msg->subtype;
    switch(subtype)
    {
        case PROTOCOL_TASK_DATA_WAY_MCU:
            {
                uint32_t type = msg->param;
                gwin_protocol_send_cmd_to_mcu(type);
            }
            break;

        default:
            GWIN_DEBUG("Error : subtype of send msg is unknown %d !!!", subtype);
            break;
    }
}


/**
 * @brief 任务初始化
 */
void gwin_protocol_task_init(void)
{
    #if (GWIN_PROT_RX_IRQ && !GWIN_PROT_RX_IRQ_RTOS_QUEUE)
    _os_timer_create(uart_rx, 100, TRUE, 0, gwin_protocol_uart_rx_callback);
    GWIN_OS_TIMER_ASSERT(_os_timer_handle(uart_rx));
    #endif

    _os_timer_create(uart_tx, 100, FALSE, 0, gwin_protocol_uart_tx_callback);
    GWIN_OS_TIMER_ASSERT(_os_timer_handle(uart_tx));

    #if GWIN_PROT_RX_IRQ
    gwin_fifo_init(&protocol_fifo_rx_mcu.fifo, protocol_fifo_rx_mcu.buf, sizeof(protocol_fifo_rx_mcu.buf));
    gwin_fifo_init(&protocol_list_rx_mcu.fifo, (uint8_t *)protocol_list_rx_mcu.buf, sizeof(protocol_list_rx_mcu.buf));
    #endif
    #if (GWIN_PROT_RX_IRQ && !GWIN_PROT_RX_IRQ_RTOS_QUEUE)
    _os_timer_start(uart_rx, 0);
    #endif

    gwin_fifo_init(&protocol_fifo_tx_mcu.fifo, protocol_fifo_tx_mcu.buf, sizeof(protocol_fifo_tx_mcu.buf));
    gwin_fifo_init(&protocol_list_tx_mcu.fifo, (uint8_t *)protocol_list_tx_mcu.buf, sizeof(protocol_list_tx_mcu.buf));

    gwin_uart_interrupt_set_callback(gwin_protocol_recv_from_mcu);

    os_msg_queue_create(&gwin_protocol_queue_handle, GWIN_PROTOCOL_TASK_QUEUE_MAX_NUM, sizeof(gwin_protocol_task_msg_t));

    os_task_create(&gwin_protocol_task_handle, "gwin_protocol_task", gwin_protocol_task, NULL, GWIN_PROTOCOL_TASK_STACK_SIZE, GWIN_PROTOCOL_TASK_PRIORITY);

    protocol_task_init = 1;
}

/**
 * @brief 发送消息
 */
uint8_t gwin_send_msg_to_protocol_task(gwin_protocol_task_msg_t *p_msg)
{
    if (!protocol_task_init) return 0;

    os_msg_send(gwin_protocol_queue_handle, p_msg, 0);
    return 1;
}


#if GWIN_PROT_RX_IRQ
/**
 * @brief 定时器 接收
 */
static void gwin_protocol_uart_rx_callback(void *arg)
{
    #if (!GWIN_PROT_RX_IRQ_RTOS_QUEUE)
    _os_timer_clear(uart_rx);
    #endif

    gwin_protocol_task_msg_t msg = { 0 };
    msg.type = PROTOCOL_TASK_MSG_TYPE_TIMER;
    msg.subtype = PROTOCOL_TASK_MSG_TIMER_SUBTYPE_UART_RX;
    gwin_send_msg_to_protocol_task(&msg);
}
#endif

/**
 * @brief 定时器 延时发送循环
 */
static void gwin_protocol_uart_tx_callback(void *arg)
{
    _os_timer_clear(uart_tx);

    gwin_protocol_task_msg_t msg = { 0 };
    msg.type = PROTOCOL_TASK_MSG_TYPE_TIMER;
    msg.subtype = PROTOCOL_TASK_MSG_TIMER_SUBTYPE_UART_TX;
    gwin_send_msg_to_protocol_task(&msg);
}

/**
 * @brief 任务
 */
static void gwin_protocol_task(void *arg)
{
    gwin_protocol_task_msg_t msg;

    while (1)
    {
        if (os_msg_recv(gwin_protocol_queue_handle, &msg, 0xFFFFFFFF) == true)
        {
            switch(msg.type)
            {
                case PROTOCOL_TASK_MSG_TYPE_TIMER:
                    gwin_protocol_task_timer_msg_handle(&msg);
                    break;

                case PROTOCOL_TASK_MSG_TYPE_RECV:
                    #if (GWIN_PROT_TYPE == GWIN_PROT_TYPE_BLE)
                    gwin_main_extern_action(MAIN_TASK_MSG_EX_ACT_SUBTYPE_WAKEUP);
                    #endif
                    gwin_protocol_task_recv_msg_handle(&msg);
                    #if (GWIN_PROT_TYPE == GWIN_PROT_TYPE_WIFI || GWIN_PROT_TYPE == GWIN_PROT_TYPE_MESH)
                    if (msg.subtype != PROTOCOL_TASK_DATA_WAY_REMOTE
                            && msg.subtype != PROTOCOL_TASK_DATA_WAY_LESHI_REMOTE
                            && msg.subtype != PROTOCOL_TASK_DATA_WAY_PINGTUOXIONG_REMOTE)
                    #endif
                    {
                        gwin_main_extern_action(MAIN_TASK_MSG_EX_ACT_SUBTYPE_FUNC_START);
                    }
                    break;

                case PROTOCOL_TASK_MSG_TYPE_SEND:
                    gwin_protocol_task_send_msg_handle(&msg);
                    break;
            }
        }
    }
}


/*-------------------------- END OF FILE ------------------------------------*/

